﻿///////////////////////////////////////////////////////////////////////////////
// File:        EventLoop.hpp
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#ifndef NIO_NET_EVENTLOOP_HPP_
#define NIO_NET_EVENTLOOP_HPP_

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif

#include <boost/noncopyable.hpp>
#include <boost/function.hpp>
#include <nio/Types.hpp>
#include <nio/base/TimeUtil.hpp>
#include <nio/base/LockGuard.hpp>
#include <nio/base/Mutex.hpp>
#include <nio/base/Queue.hpp>
#include <nio/net/Reactor.hpp>

namespace nio
{
    namespace net
    {
        class EventLoop : public boost::noncopyable
        {
        public:
            enum State
            {
                READY,
                RUNNING,
                EXITING,
                EXIT
            };

        public:
            EventLoop(void);
            ~EventLoop(void);

            ReactorPtr& getReactor(void) { return reactor_; }
            State getState(void) const { return state_; }

            void queue(boost::function<void(void)> handler);
            void run(void);
            void stop(void);

            void setFrameTime(base::time_t time) { cnfFrameTime_ = time; }
            base::time_t getFrameUseTime(void) const { return frameUseTime_; }

        private:
            void setState(State state) { state_ = state; }
            void doStop(void) { setState(EXITING); }

        private:
            ///////////////////////////////////////////////////////////////////
            struct _stEvent
            {
                base::time_t time;
                boost::function<void(void)> handler;
            };

            typedef base::Queue<struct _stEvent, base::Mutex>   EventQueue;

            ///////////////////////////////////////////////////////////////////
            class Checker
            {
            public:
                Checker(EventLoop* loop)
                    : loop_(loop)
                    , now_(base::TimeUtil::fromStartup())
                {

                }
                ~Checker(void) { }

                bool check(struct _stEvent& event)
                {
                    if (loop_->getState() != EXITING)
                        return (event.time <= now_);
                    else
                        return true;
                }

            private:
                EventLoop*      loop_;
                base::time_t    now_;
            };
            ///////////////////////////////////////////////////////////////////

        private:
            State           state_;
            base::time_t    cnfFrameTime_;
            base::time_t    frameUseTime_;
            ReactorPtr      reactor_;
            EventQueue      events_;
        };
    }
}

#endif //NIO_NET_EVENTLOOP_HPP_
